home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / gus / gusdk210.zip / README.PAT < prev    next >
Text File  |  1993-05-19  |  7KB  |  147 lines

  1.  
  2. TITLE:      Advanced Gravis Tech Note #19
  3. AREA:       PROGRAMMING
  4. DATE:       May 19, 1993
  5. KEY WORDS:  ULTRASOUND PROGRAMMING MCI PATCH CACHE
  6.  
  7. SUBJECT: Implementation of Patch Caching for the Gravis UltraSound
  8.  
  9. The following describes the specific implementation of patch caching in
  10. the current release of the Ultrasound drivers for Windows 3.1.
  11.  
  12. The basic idea of patch caching involves setting up a 128 element WORD
  13. array whose elements correspond to each of 128 patches, and setting bits
  14. in each WORD to indicate which MIDI channels use a specific patch.  The
  15. midiOutCachePatches call sends the driver a pointer to this array, along
  16. with a flag indicating the action to be taken.  The midiOutCacheDrumPatches
  17. call is used in a similar fashion to request that drum patches be cached.
  18.  
  19. Two things conspire to make the implementation and use of patch caching more
  20. difficult than it should be.  First, the media player app that ships with
  21. MS Windows incorrectly responds to the return value MMSYSERR_NOMEM, when
  22. it calls midiOutCachePatches with the MIDI_CACHE_BESTFIT flag set.  A direct
  23. reading of the documentation indicates that _BESTFIT should cause the driver
  24. to attempt to load the specified patches, and if it is not possible to fit
  25. all of the patches into memory, to change the PATCHARRAY to reflect which
  26. patches were cached, and return MMSYSERR_NOMEM.  Unfortunately, if the driver
  27. responds according to this description, the media player decides that no
  28. midi devices are present, and puts up an ugly message box to that effect!
  29.  
  30. This forces a driver, including the Ultrasound, to always respond with
  31. MMSYSERR_NOERROR in order to have the media player proceed.  Fortunately,
  32. media player does not complain when the PATCHARRAY is changed to reflect
  33. which patches were loaded, so another app using this function can do a
  34. compare on a copy of the PATCHARRAY sent with that returned to determine the
  35. current state.  If midiOutCachePatches is called with MIDI_CACHE_ALL set,
  36. the driver does respond with MMSYSERR_NOMEM according to spec.
  37.  
  38. This might lead the alert victim, er, developer, to say, "I'll just use
  39. _CACHE_ALL, check the return value, then use _BESTFIT to do it for real.",
  40. in order to get around the problem of maintaining a separate copy of the
  41. PATCHARRAY.
  42. Well, there are a couple of gotchas lurking down that route.  First, the
  43. driver is supposed to clear the PATCHARRAY if _CACHE_ALL fails, which it
  44. does.  This means you still need that duplicate copy of the PATCHARRAY, in
  45. some form or the other.  Also, with the original patches released with the
  46. board, there was no single number giving the total size of the patch in the
  47. first part of the header. This meant that if an app does a _CACHE_ALL to
  48. avoid doing a compare on the array, the driver had to essentially attempt to
  49. load everthing before determining it had run out of memory(bummer, huh?)!
  50. The latest patches have that precious number in the first header, so that
  51. part of the problem can be remedied.
  52.  
  53. The second problem is caused by the current implementation of the Ultrasound
  54. "firmware".  There is no way currently to selectively delete and replace a
  55. single patch in Ultrasound patch memory.  This fact, coupled with the media
  56. player's behaviour, has forced a particular implementation of the basic
  57. cache patch messages.
  58. Specifically, the media player ALWAYS calls midiOutCachePatches prior to
  59. midiOutCacheDrumPatches.  To accomodate this sequence, the Ultrasound driver
  60. clears all of patch memory on receiving _CACHEPATCHES, but does NOT clear
  61. patch memory on receiving _CACHEDRUMPATCHES. Patch memory is not cleared
  62. when the device is closed, however, so a subsequent call to cache patches
  63. with _exactly_ the same PATCHARRAY does not cause the driver to clear memory
  64. and reload the patches.
  65. I highlighted _exactly_, since the driver will flush memory if there is any
  66. mismatch.  It would seem smarter to accept a subset of what's in memory as a
  67. good reason not to flush, but then along comes a _CACHEDRUM and there's
  68. suddenly not enough memory for the drums, when really there should've been.
  69.  
  70.  
  71. What happens when MIDI_UNCACHE is set?  If the message is _CACHEPATCHES, all
  72. of patch memory is cleared.  The local state of the patches, both melodic and
  73. drums, is updated such that a subsequent call with MIDI_CACHE_QUERY reveals
  74. no patches are currently cached.  If MIDI_UNCACHE is set and _CACHEDRUMPATCHES
  75. is sent, ONLY the drum memory and KEYARRAY is cleared.  What is implied is
  76. that, using the standard cache patch messages, drum patch memory can be
  77. cleared and reloaded without affecting melodic patch memory, but not vice
  78. versa.  Drum memory starts at the end of melodic memory.
  79.  
  80. A custom pair of cache patch messages has been implemented to accomodate
  81. Howling Dog's Power Chords application.  The implementation is basically a
  82. mirror of the standard messages, in that the drums have priority over the
  83. melodics.  Also, there was no need to propagate the workaround for media
  84. player, so MMSYSERR_NOMEM is properly returned in a low memory situation.
  85. Details on the use of these messages is available if requested.  The type of
  86. app that would benefit from their use would be one that wants a drum set
  87. always present, and relatively static, and expects most patch changes to be
  88. melodic.
  89.  
  90. Here are the manufacturer and product id's needed to identify the
  91. Ultrasound driver:
  92.  
  93. #define MM_GRAVIS               34
  94. #define MM_ULTRASND_WAVEOUT     13
  95. #define MM_ULTRASND_WAVEIN      14
  96. #define MM_ULTRASND_MIDIOUT     15
  97. #define MM_ULTRASND_AUX         16
  98. #define MM_ULTRASND_MIDISYNTH   17
  99. #define MM_ULTRASND_MIDIIN      18
  100.  
  101.  
  102. Code Snippet for getting patch memory available...
  103.  
  104. #define MODM_QUERYMEM   1000
  105.  
  106.     case IDM_MEMAVAIL:
  107. if (midiOutOpen (&hMidiOut, (UINT) iUltraMidiID, NULL, 0L, 0L))
  108. {
  109.     MessageBeep (MB_ICONEXCLAMATION) ;
  110.     MessageBox (hWnd, "Cannot open Ultrasound Device",
  111.     szAppName, MB_OK | MB_ICONEXCLAMATION) ;
  112. }
  113. else
  114. {
  115.     midiOutMessage(hMidiOut, MODM_QUERYMEM,
  116.                   (DWORD) ((LPLONG) &lnMemAvail), 0L);
  117.     midiOutClose (hMidiOut);
  118.     wsprintf(S,"Patch Memory Availiable: %ld Bytes\r\n",
  119.              lnMemAvail);
  120.     MessageBox (hWnd, S, szAppName,
  121.                 MB_ICONINFORMATION | MB_OK) ;
  122. }
  123.  
  124. return 0;
  125.  
  126.  
  127. Mixer programming info...
  128.  
  129.     To Set the mic, line, and output enable, OR on the appropriate bits and
  130.     send an AUXDM_MIXCTL message to the aux driver...
  131.  
  132.     #define AUXDM_MIXCTL            70  // Driver Specific Message
  133.     #define SELECT_MIC      0x01L
  134.     #define SELECT_LINE     0x02L
  135.     #define ENABLE_OUT      0x04L
  136.     #define GET_CONTROL     0L
  137.     #define SET_CONTROL     1L
  138.  
  139.  
  140.     dwInpMask |= ENABLE_OUT; // etc...
  141.  
  142.     auxOutMessage(iAuxID, AUXDM_MIXCTL, dwInpMask, SET_CONTROL);
  143.  
  144.     To get the current state, do the following...
  145.  
  146.     dwInpMask = auxOutMessage(iAuxID, AUXDM_MIXCTL, dwInpMask, GET_CONTROL);
  147.